package com.msh.frame.client.common;

import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 构造树结构
 *
 * @author 时虎
 */
public interface ITreeConstructor<T extends ITreeConstructor<T>> {

  /**
   * 标识
   *
   * @return code
   */
  Object key();

  /**
   * 父标识
   *
   * @return 父code
   */
  Object parentKey();

  /**
   * 是否一级
   *
   * @return 是否
   */
  boolean layerOne();

  /**
   * 获取子节点
   *
   * @return 子节点
   */
  List<T> getChildren();

  /**
   * 设置子节点
   *
   * @param list 子节点
   * @return 当前对象
   */
  T setChildren(List<T> list);

  /**
   * 构建树结构
   */
  static <T extends ITreeConstructor<T>> List<T> tree(List<T> list) {
    if (CollectionUtils.isEmpty(list)) {
      return Collections.emptyList();
    }
    List<T> layerOneList = new LinkedList<>();
    Map<Object, T> map = new HashMap<>(list.size() * 2);
    list.forEach(t -> {
      Object code = t.key();
      map.put(code, t);
      if (t.layerOne()) {
        layerOneList.add(t);
      }
    });
    list.forEach(t -> {
      Object parentCode = t.parentKey();
      T tParent = map.get(parentCode);
      if (null != tParent) {
        if (null == tParent.getChildren()) {
          tParent.setChildren(new LinkedList<T>());
        }
        tParent.getChildren().add(t);
      }
    });
    list.forEach(t -> {
      if (null == t.getChildren()) {
        t.setChildren(Collections.emptyList());
      }
    });
    return layerOneList;
  }

  /**
   * 树子节点处理（从上向下遍历）
   * @param list 子节点循环
   * @param consumer 处理方式
   */
  static <T extends ITreeConstructor<T>> void treeChildrenDispose(List<T> list, Consumer<List<T>> consumer){
    if(CollectionUtils.isEmpty(list)){
      return;
    }
    consumer.accept(list);
    list.forEach(t->{
      List<T> children = t.getChildren();
      if(!CollectionUtils.isEmpty(children)){
        consumer.accept(children);
        treeChildrenDispose(children, consumer);
      }
    });
  }

  /**
   * 树节点处理
   * @param t 父节点
   * @param list 树列表
   * @param preConsumer 前置处理（从上向下遍历）
   * @param postConsumer 后置处理（从下向上遍历）
   * @param <T> 树结构类
   */
  static <T extends ITreeConstructor<T>> void treeChildrenDispose(T t, List<T> list, BiConsumer<T, List<T>> preConsumer, BiConsumer<T, List<T>> postConsumer){
    if(null != preConsumer){
      preConsumer.accept(t, list);
    }
    if(!CollectionUtils.isEmpty(list)){
      list.forEach(o->{
        treeChildrenDispose(o, o.getChildren(), preConsumer, postConsumer);
      });
    }
    if(null != postConsumer){
      postConsumer.accept(t, list);
    }
  }
}
